//
//  BluetoothManager.swift
//  EarbudsCommon
//
//  Created by 李然 on 2024/4/28.
//

import Foundation
import RxCocoa
import RxSwift
import CRPEarPhone
import CoreBluetooth
import MoyoungLib
import EarbudsDatabase

public class BluetoothManager: NSObject {
    
    public static let shared = BluetoothManager()
    
    // 时间同步定时器
    private var timer: Disposable?

    /// 是否连接
    public var isConnected: Bool {
        switch self.connectState.value {
        case .connected, .syncing, .syncSuccess:
            return true
        default:
            return false
        }
    }
    
    /// 是否绑定了设备，SDK的有延迟，使用本地 Device
    public var isBindedDevice: Bool {
        return Device.current() != nil
    }
    
    /// 当前连接的设备
    public lazy var connectDiscovery = BehaviorRelay<CRPDiscovery?>(value: nil)
    
    /// 返回当前的⽿机仓的连接状态
    public lazy var connectState = BehaviorRelay<CRPEarPhone.CRPState>(value: .unbind)
    /// 返回当前蓝⽛状态
    public lazy var bleState = BehaviorRelay<CRPBluetoothState>(value: .unknown)
    /// 接收表盘相关信息
    public lazy var receiveWatchFaceConfig = BehaviorRelay<CRPWatchFaceConfigModel?>(value: nil)
    /// 接收语⾔相关信息
    public lazy var receiveLanguageConfig = BehaviorRelay<CRPLanguageConfigModel?>(value: nil)
    /// 接收息屏时⻓信息
    public lazy var receiveAutoLockTime = BehaviorRelay<Int?>(value: nil)
    /// 接收电量信息
    public lazy var receiveBatteryInfo = BehaviorRelay<CRPBatteryInfoModel?>(value: nil)
    /// 接收拍照状态
    public lazy var receiveCameraAction = PublishRelay<Int>()
    /// 耳机连接状态
    public lazy var receiveEarPhoneConnectionState = BehaviorRelay<CRPEarPhoneConnectStateModel?>(value: nil)
    /// 接收闹钟信息
    public lazy var receiveAlarm = BehaviorRelay<CRPAlarmConfigModel?>(value: nil)
    /// 接收天⽓信息
    public lazy var requestWeather = PublishRelay<Void>()
    /// 收到今天耳机使用时间数据
    public lazy var receiveUseTime = BehaviorRelay<Void>(value: ())
    
    /// 开始扫描
    /// - Returns: 设备列表
    public func scan() -> Observable<[CRPEarPhone.CRPDiscovery]> {
        
        let response = Observable.create { observer in
            
            var discoverys: [CRPDiscovery] = []
            
            CRPEarPhoneSDK.sharedInstance.scan(10) { newDiscoveries in
                newDiscoveries.forEach { discovery in
                    if let mac = discovery.mac, !discoverys.contains(where: { $0.mac == mac }) {
                        discoverys.append(discovery)
                        observer.onNext(discoverys)
                    }
                }
            } completionHandler: { result, error in
                if error != .none {
                    observer.onError(ErrorUtil.error(code: error.rawValue, message: "sdk scan error \(error.rawValue)"))
                } else {
                    observer.onCompleted()
                }
            }

            return Disposables.create {
                CRPEarPhoneSDK.sharedInstance.interruptScan()
            }
        }
        
        return response
    }
    
    /// 连接某一设备
    public func connect(_ device: CRPEarPhone.CRPDiscovery) {
        guard bleState.value == .poweredOn else { return }
        CRPEarPhoneSDK.sharedInstance.connet(device)
        let device = Device.init(discovery: device)
        device.save()
    }
    
    /// 移除设备
    public func remove() {
        Device.current()?.remove()
        CRPEarPhoneSDK.sharedInstance.remove()
    }
    
    /// 中断扫描
    public func interrupScan() {
        CRPEarPhoneSDK.sharedInstance.interruptScan()
    }

    /// 设置表盘
    public func sendDisplayWatchFace(index: Int) {
        CRPEarPhoneSDK.sharedInstance.sendDisplayWatchFace(index: index)
    }
    
    /// 查询语⾔配置调⽤queryDeviceLanguage或者⽿机仓上切换语⾔都将通过receiveLanguageConfig回调语⾔相关信息
    public func queryDeviceLanguage() {
        CRPEarPhoneSDK.sharedInstance.queryDeviceLanguage()
    }

    /// 设置语⾔
    public func sendDeviceLanguage(language: Int) {
        CRPEarPhoneSDK.sharedInstance.sendDeviceLanguage(language: language)
    }
    
    /// 查询息屏时⻓调⽤queryAutoLockTime或者⽿机仓上设置息屏时⻓都将通过receiveAutoLockTime回调相关信息
    public func queryAutoLockTime() {
        CRPEarPhoneSDK.sharedInstance.queryAutoLockTime()
    }
    
    /// 设置息屏时⻓(单位为秒，0xFF表示常亮)
    public func sendAutoLockTime(time: Int) {
        CRPEarPhoneSDK.sharedInstance.sendAutoLockTime(time: time)
    }
    
    /// 查询勿扰模式
    public func queryDoNotDistrubTime() -> Observable<CRPDoNotDistrubTimeModel> {
        return Single<CRPDoNotDistrubTimeModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryDoNotDistrubTime { model in
                ob(.success(model))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置勿扰模式
    public func sendDoNotDistrubTime(model: CRPDoNotDistrubTimeModel) {
        CRPEarPhoneSDK.sharedInstance.sendDoNotDistrubTime(model: model)
    }
    
    /// 查询电量调⽤queryBattery或者电量发⽣变化都将通过receiveBatteryInfo(model: CRPBatteryInfoModel)回调相关信息
    public func queryBattery() {
        CRPEarPhoneSDK.sharedInstance.queryBattery()
    }
    
    /// 进⼊拍照界⾯
    public func enterCameraView() {
        CRPEarPhoneSDK.sharedInstance.enterCameraView()
    }
    
    /// 退出拍照界⾯
    public func exitCameraView() {
        CRPEarPhoneSDK.sharedInstance.exitCameraView()
    }
    
    /// 查询推送⽀持类型
    public func queryMessageConfig() -> Observable<[Int]> {
        return Single<[Int]>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryMessageConfig { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询消息推送状态
    public func queryMessageState() -> Observable<[Int]> {
        return Single<[Int]>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryMessageState { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置消息推送状态
    public func setMessageState(_ states: [Int]) {
        CRPEarPhoneSDK.sharedInstance.setMessageState(states)
    }
    
    /// 查询EQ状态
    public func queryEQSetting() -> Observable<CRPEQSetttingModel> {
        return Single<CRPEQSetttingModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEQSetting { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置EQ状态
    public func sendEQSetting(model: CRPEQSetttingModel) {
        CRPEarPhoneSDK.sharedInstance.sendEQSetting(model: model)
    }
    
    /// 查询ACN状态
    public func queryANCMode() -> Observable<CRPANCSetttingModel> {
        return Single<CRPANCSetttingModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryANCMode { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置ACN状态
    public func sendANCMode(model: CRPANCSetttingModel) {
        CRPEarPhoneSDK.sharedInstance.sendANCMode(model: model)
    }
    
    /// 查询⽿机连接状态调⽤queryEarPhoneConnectionState或者连接状态变化都将通过receiveEarPhoneConnectionState回调相关信息
    public func queryEarPhoneConnectionState() {
        CRPEarPhoneSDK.sharedInstance.queryEarPhoneConnectionState()
    }
    
    /// 查询是否⽀持断开后被其他设备连接
    public func querySupportOtherConnect() -> Observable<Bool> {
        return Single<Bool>.create { ob in
            CRPEarPhoneSDK.sharedInstance.querySupportOtherConnect { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询按键⽀持信息
    public func querySupportKeyAction() -> Observable<CRPButtonFuncSupportTypeModel> {
        return Single<CRPButtonFuncSupportTypeModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.querySupportKeyAction { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询所有按键配置
    public func queryAllKeyAction() -> Observable<[CRPButtonFuncModel]> {
        return Single<[CRPButtonFuncModel]>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryAllKeyAction { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置按键功能
    public func sendKeyAction(model: CRPButtonFuncModel) {
        CRPEarPhoneSDK.sharedInstance.sendKeyAction(model: model)
    }

    /// 重启
    public func reboot() {
        CRPEarPhoneSDK.sharedInstance.reboot()
    }
    
    /// 恢复出厂设置
    public func reset() {
        CRPEarPhoneSDK.sharedInstance.reset()
    }
    
    /// 关机
    public func shutDown() {
        CRPEarPhoneSDK.sharedInstance.shutDown()
    }
    
    /// 固件升级
    private lazy var receiveRTKUpdrade = PublishRelay<(state: CRPOTAState, progress: Int)>()
    public func startUpgradeFromFile(path: String) -> Observable<(state: CRPOTAState, progress: Int)> {
        CRPEarPhoneSDK.sharedInstance.startUpgradeFromFile(path: path)
        return self.receiveRTKUpdrade.asObservable()
    }
    
    /// 查询当前⽿机⾳量和播放状态
    public func queryEarPhoneAudio() -> Observable<CRPEarPhoneAudioModel> {
        return Single<CRPEarPhoneAudioModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneAudio { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询⽿机仓Mac地址
    public func queryEarPhoneBoxMacAddress() -> Observable<String> {
        return Single<String>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneBoxMacAddress { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询⽿机Mac地址
    public func queryEarPhoneMacAddress() -> Observable<String> {
        return Single<String>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneMacAddress { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 查询闹钟，使⽤queryAlarm⽅法或者⽿机仓⼿动修改闹钟将通过receiveAlarm回调⽅法返回闹钟列表
    public func queryAlarm() {
        CRPEarPhoneSDK.sharedInstance.queryAlarm()
    }
    
    /// 添加闹钟
    public func addAlarm(alarm: CRPAlarmModel) {
        CRPEarPhoneSDK.sharedInstance.addAlarm(alarm: alarm)
    }
    
    /// 删除闹钟
    public func deleteAlarm(id: Int) {
        CRPEarPhoneSDK.sharedInstance.deleteAlarm(id: id)
    }
    
    /// 清除所有闹钟
    public func clearAllAlarm() {
        CRPEarPhoneSDK.sharedInstance.clearAllAlarm()
    }
    
    /// 修改闹钟
    public func sendAlarm(alarm: CRPAlarmModel) {
        CRPEarPhoneSDK.sharedInstance.sendAlarm(alarm: alarm)
    }
    
    /// 获取耳机仓版本信息
    public func queryEarPhoneBoxVer() -> Observable<CRPEarPhoneBoxVersionModel> {
        return Single<CRPEarPhoneBoxVersionModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneBoxVer { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 获取耳机版本信息
    public func queryEarPhoneVer() -> Observable<CRPEarPhoneVersionModel> {
        return Single<CRPEarPhoneVersionModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneVer { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 获取⽿机仓配置信息
    public func queryEarPhoneBoxConfig() -> Observable<CRPEarPhoneBoxInfoModel> {
        return Single<CRPEarPhoneBoxInfoModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryEarPhoneBoxConfig { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置实时天⽓
    public func sendWeather(weather: CRPWeather) {
        CRPEarPhoneSDK.sharedInstance.sendWeather(weather: weather)
    }
    
    /// 设置天⽓预报信息
    public func sendForecastWeather(weathers: [CRPForecastWeather]) {
        CRPEarPhoneSDK.sharedInstance.sendForecastWeather(weathers: weathers)
    }
    
    /// 查询联系⼈信息
    public func queryContactConfig() -> Observable<CRPContactConfigModel> {
        return Single<CRPContactConfigModel>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryContactConfig { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置联系人
    public func sendContact(contacts: [CRPContact]) {
        CRPEarPhoneSDK.sharedInstance.sendContact(contacts: contacts)
    }
    
    /// 清除联系人
    public func clearContact() {
        CRPEarPhoneSDK.sharedInstance.clearContact()
    }
    
    /// 查询联系⼈⽀持符号
    public func queryContactSupportSymbol() -> Observable<[String]> {
        return Single<[String]>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryContactSupportSymbol { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置时间格式
    public func sendTimeFormat(_ type: Int) {
        CRPEarPhoneSDK.sharedInstance.sendTimeFormat(type)
    }

    /// 查询时间格式 0表示 12小时  1表示24小时
    public func queryTimeformat() -> Observable<Int> {
        return Single<Int>.create { ob in
            CRPEarPhoneSDK.sharedInstance.queryTimeformat { value in
                ob(.success(value))
            }
            return Disposables.create()
        }.asObservable()
    }
    
    /// 设置音量
    public func sendEarPhoneVolume(value: Int) {
        CRPEarPhoneSDK.sharedInstance.sendEarPhoneVolume(value: value)
    }
    
    /// 查找耳机
    public func sendFindEarPhone(state: Int, leftEar: Int, rightEar: Int) {
        CRPEarPhoneSDK.sharedInstance.sendFindEarPhone(state: state, leftEar: leftEar, rightEar: rightEar)
    }
    
    /// 检查最新固件版本
    public func checkLatest(_ version: String, _ mac: String) -> Single<Version?> {
        return Single<Version?>.create { single in
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
                let v = Version.init(version: "9.9.9", md5: "666666", fileUrl: "ota.ufw")
                single(.success(v))
            }
            return Disposables.create()
        }
    }
}

// MARK: - 自定义方法
extension BluetoothManager {
    
    /// 初始化设置
    public func setConfig(isLogEnabel: Bool = false) {
        CRPEarPhoneSDK.sharedInstance.showLog = isLogEnabel
        CRPEarPhoneSDK.sharedInstance.delegate = self
        self.addTimeSynchronisedTask()
        self.syncDataWhenConnected()
    }
    
    /// 添加时间同步的定时器
    private func addTimeSynchronisedTask() {
        let foregroundObservable = UIApplication.rx.didBecomeActive.map { true }
        let backgroundObservable = UIApplication.rx.willResignActive.map { false }
        
        let appIsActive = Observable<Bool>.merge([foregroundObservable, backgroundObservable])
            .startWith(UIApplication.shared.applicationState == .active)
        appIsActive.filter { $0 }.subscribe(onNext: {  _ in
            self.timer = Observable<Int>.interval(RxTimeInterval.seconds(2 * 3600), scheduler: MainScheduler.instance)
                .startWith(0)
                .subscribe(onNext: { _ in
                    guard self.connectState.value == .connected else { return }
                    CRPEarPhoneSDK.sharedInstance.sendTime()
                })
        }).disposed(by: rx.disposeBag)

        appIsActive.filter { !$0 }.subscribe(onNext: { _ in
            self.timer?.dispose()
        }).disposed(by: rx.disposeBag)
    }
    
    /// 连接成功后同步一些数据
    private func syncDataWhenConnected() {
        self.connectState.filter { $0 == .connected }
            .distinctUntilChanged()
            .subscribe(onNext: { _ in
                CRPEarPhoneSDK.sharedInstance.sendTime()
                CRPEarPhoneSDK.sharedInstance.queryBattery()
                
                for id in 0...6 {
                    CRPEarPhoneSDK.sharedInstance.queryEarPhoneUseTime(id: id)
                }
            }).disposed(by: rx.disposeBag)
    }
    
    /// 更新单日步数
    /// - Parameter model: SDK返回的数据
    private func updateUsetime(with sdkModel: CRPEarPhoneUseTimeModel) {
        let date = Date() - sdkModel.id.days
        let oldValue = EasepodsDB.queryDay(type: UsetimeModel.self, from: date)
        
        var model: UsetimeModel!
        if let oldValue = oldValue {
            model = oldValue
        } else {
            model = UsetimeModel()
            model.date = date
            EasepodsDB.save(object: model)
        }
        let newList =  sdkModel.earPhoneUseTime.map { timeModel in
            let detail = UsetimeDetailModel()
            detail.typeRawValue = timeModel.type.rawValue
            detail.startTimeMin = timeModel.startTimeMin
            detail.useTimeMin = timeModel.useTimeMin
            return detail
        }
        let mac = Device.current()?.macAddress ?? ""
        model.update(newList, usageFrequency: sdkModel.usageFrequency, address: mac)
        
        if date.isToday {
            receiveUseTime.accept(())
        }
    }
}

//MARK: - CRPManagerDelegate代理方法
extension BluetoothManager: CRPManagerDelegate {
    
    public func didState(_ state: CRPEarPhone.CRPState) {
        self.connectState.accept(state)
        let discovery = CRPEarPhoneSDK.sharedInstance.currentCRPDiscovery
        BluetoothManager.shared.connectDiscovery.accept(discovery)
    }
    
    public func didBluetoothState(_ state: CRPEarPhone.CRPBluetoothState) {
        self.bleState.accept(state)
        switch state {
        case .poweredOff:
            self.connectState.accept(.disconnected)
        default:
            break
        }
    }
    
    public func receiveOTA(_ state: CRPEarPhone.CRPOTAState, _ progress: Int) {
        log.debug("receiveOTA \(state) , progress \(progress)")
        self.receiveRTKUpdrade.accept((state: state, progress: progress))
    }
    
    public func receiveWatchFaceConfig(config: CRPEarPhone.CRPWatchFaceConfigModel) {
        receiveWatchFaceConfig.accept(config)
    }
    
    public func receiveLanguageConfig(config: CRPEarPhone.CRPLanguageConfigModel) {
        receiveLanguageConfig.accept(config)
    }
    
    public func receiveAutoLockTime(time: Int) {
        receiveAutoLockTime.accept(time)
    }
    
    public func receiveBatteryInfo(model: CRPEarPhone.CRPBatteryInfoModel) {
        receiveBatteryInfo.accept(model)
    }
    
    public func receiveCameraAction(state: Int) {
        receiveCameraAction.accept(state)
    }
    
    public func receiveEarPhoneConnectionState(model: CRPEarPhone.CRPEarPhoneConnectStateModel) {
        receiveEarPhoneConnectionState.accept(model)
    }
    
     public func receiveAlarm(alarmConfig: CRPEarPhone.CRPAlarmConfigModel) {
        receiveAlarm.accept(alarmConfig)
    }

    public func recevieWeather() {
        requestWeather.accept(())
    }
    
    public func receivePhoneNumber(number: String) {
        PhoneCall.sendContactName(number: number)
    }
    
    public func receiveEarPhoneUseTimeData(model: CRPEarPhone.CRPEarPhoneUseTimeModel) {
        updateUsetime(with: model)
    }
}
